//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Graphics/Resources/Program.h"
#include "Graphics/Systems/BatchRender.h"
#include "Graphics/Systems/Viewport.h"

namespace Engine
{
namespace Graphics
{

	struct FontBatch;
	
	class IFont;
	SHARED_POINTER( IFont );
	

	class BitmapFont;
	SHARED_POINTER( BitmapFont );
	

	class VectorFont;
	SHARED_POINTER( VectorFont );



	//
	// Font
	//

	class IFont : public Resource
	{
	// types
	public:
		
		//
		// Glyph
		//
		struct Glyph
		{
			rect	texcoord;
			vec2	size;
			vec2	offsetX;
			float	offsetY;	// from top coord to baseline
			bool	empty;
			///
			Glyph () : offsetY(0.0f), empty(true) {}
			
			explicit
			Glyph (float advanceX) : offsetX(0.0f, advanceX), offsetY(0.0f), empty(true) {}
		};


	// methods
	protected:
		template <typename GlyphReader>
		static void _Draw (	const ViewportPtr &viewport,
							const BatchRenderPtr &batchRender,
							const GlyphReader &glyphReader,
							const FontBatch &params,
							const rect &region,
							uni_c_string text,
							bool scissor );
		
		template <typename GlyphReader>
		static void _Draw (	const ViewportPtr &viewport,
							const BatchRenderPtr &batchRender,
							const GlyphReader &glyphReader,
							const FontBatch &params,
							const rect &region,
							const ext_string &text,
							bool scissor );
		
		template <typename GlyphReader>
		static void _GetTextDimensions (const ViewportPtr &viewport,
										const GlyphReader &glyphReader,
										const FontBatch &params,
										uni_c_string text,
										OUT vec2 &dim,
										OUT usize &lineLength);
		
		template <typename GlyphReader>
		static void _GetFormattedText (	const ViewportPtr &viewport,
										const GlyphReader &glyphReader,
										float maxLineWidth,
										const FontBatch &params,
										const ext_string &text,
										const LocaleCharacters &localeChars,
										OUT ext_string &formattedText,
										OUT vec2 &dim );

		static float _CalcDefaultScale (const ViewportPtr &vp, uint heightInPixels);


	public:
		IFont (EResource::type resType, const EngineSubSystemsRef ess) : Resource( resType, ess ) {}

		virtual void Draw (const FontBatch &params, const vec2 &pos, uni_c_string text, bool scissor) = 0;
		virtual void Draw (const FontBatch &params, const rect &region, uni_c_string text, bool scissor) = 0;

		virtual void Draw (const FontBatch &params, const vec2 &pos, const ext_string &text, bool scissor) = 0;
		virtual void Draw (const FontBatch &params, const rect &region, const ext_string &text, bool scissor) = 0;

		virtual void GetTextDimensions (const FontBatch &params, uni_c_string text, OUT vec2 &dim, OUT usize &lineLength) = 0;

		virtual void GetFormattedText (const FontBatch &params, float maxLineWidth, const ext_string &text,
										const LocaleCharacters &localeChars, OUT ext_string &formattedText, OUT vec2 &dim) = 0;
	};



	//
	// Text Direction
	//

	namespace ETextDirection
	{
		enum type
		{
			_HORIZONTAL_MASK= 0x0F,
			LEFT_TO_RIGHT	= 0x01,
			RIGHT_TO_LEFT	= 0x02,

			_VERTICAL_MASK	= 0xF0,
			TOP_TO_BOTTOM	= 0x10,
			BOTTOM_TO_TOP	= 0x20,
			
			DEFAULT			= LEFT_TO_RIGHT | TOP_TO_BOTTOM
		};

		UX_ENUM_BIT_OPERATIONS( type );
	};



	//
	// Font Batch
	//

	struct FontBatch
	{
		friend class IFont;
		friend class BitmapFont;

	// types
	public:
		typedef FontBatch	Self;

	// variables
	protected:
		IFontPtr				_font;
		BatchMaterial			_material;
		vec2					_scale;
		float					_spacing;
		color4u					_color;
		ETextDirection::type	_direction;
		bool					_mulWithTextColor;	// for ext_string: new_color = _color * text_color;


	// methods
	public:
		FontBatch ();

		void Clear ();

		Self & SetColor (const color4u &color);
		Self & SetScale (const vec2 &scale);
		Self & SetScale (float value);
		Self & SetFont (const IFontPtr &font);
		Self & SetProgram (const ProgramPtr &program);
		Self & SetColorState (const RenderState::ColorState &state);
		Self & SetColorState (const RenderState::ColorStateSeparate &state);
		Self & SetSpacing (float value);
		Self & SetDirection (ETextDirection::type value);
		Self & SetMulWithTextColor (bool value);

		void Draw (const vec2 &pos, uni_c_string text, bool scissor = false);
		void Draw (const rect &region, uni_c_string text, bool scissor = false);
		
		void Draw (const vec2 &pos, const ext_string &text, bool scissor = false);
		void Draw (const rect &region, const ext_string &text, bool scissor = false);
		
		void GetTextDimensions (uni_c_string text, OUT vec2 &dim, OUT usize &lineLength) const;
		void GetFormattedText (const ext_string &text, float maxLineWidth, const LocaleCharacters &localeChars,
								OUT vec2 &dim, OUT ext_string &formatted) const;

		IFontPtr const &		GetFont ()		const	{ return _font; }
		BatchMaterial const &	GetMaterial ()	const	{ return _material; }
		BatchMaterial &			GetMaterial ()			{ return _material; }
		vec2 const &			GetScale ()		const	{ return _scale; }
	};



	// constructor
	inline FontBatch::FontBatch () :
		_scale(1.0f), _color(255), _spacing(0.1f), _direction( ETextDirection::DEFAULT ),
		_mulWithTextColor(false), _font()
	{
		RenderState::ColorState	cs;

		cs.blend		= true;
		cs.blendFuncSrc	= gl_blend_func::SRC_ALPHA;
		cs.blendFuncDst	= gl_blend_func::ONE_MINUS_SRC_ALPHA;
		cs.blendMode	= gl_blend_equation::ADD;
		cs.maskR		= true;
		cs.maskG		= true;
		cs.maskB		= true;
		cs.maskA		= true;

		_material.SetColorState( cs );
	}
		
	// Clear
	inline void FontBatch::Clear ()
	{
		*this = FontBatch();
	}

	// SetColor
	inline FontBatch & FontBatch::SetColor (const color4u &color)
	{
		_color = color;
		return *this;
	}

	// SetScale
	inline FontBatch & FontBatch::SetScale (const vec2 &scale)
	{
		_scale = scale;
		return *this;
	}
	
	// SetScale
	inline FontBatch & FontBatch::SetScale (float value)
	{
		_scale = vec2( value );
		return *this;
	}

	// SetFont
	inline FontBatch & FontBatch::SetFont (const IFontPtr &font)
	{
		_font = font;
		return *this;
	}

	// SetProgram
	inline FontBatch & FontBatch::SetProgram (const ProgramPtr &program)
	{
		_material.SetProgram( program );
		return *this;
	}

	// SetColorState
	inline FontBatch & FontBatch::SetColorState (const RenderState::ColorState &state)
	{
		_material.SetColorState( state );
		return *this;
	}

	// SetColorState
	inline FontBatch & FontBatch::SetColorState (const RenderState::ColorStateSeparate &state)
	{
		_material.SetColorState( state );
		return *this;
	}

	// SetInterval
	inline FontBatch & FontBatch::SetSpacing (float value)
	{
		_spacing = value;
		return *this;
	}
	
	// SetDirection
	inline FontBatch & FontBatch::SetDirection (ETextDirection::type value)
	{
		_direction = value;
		return *this;
	}
	
	// SetMulWithTextColor
	inline FontBatch & FontBatch::SetMulWithTextColor (bool value)
	{
		_mulWithTextColor = value;
		return *this;
	}

	// Draw
	inline void FontBatch::Draw (const vec2 &pos, uni_c_string text, bool scissor)
	{
		_font->Draw( *this, pos, text, scissor );
	}

	// Draw
	inline void FontBatch::Draw (const rect &region, uni_c_string text, bool scissor)
	{
		_font->Draw( *this, region, text, scissor );
	}
	
	// Draw
	inline void FontBatch::Draw (const vec2 &pos, const ext_string &text, bool scissor)
	{
		_font->Draw( *this, pos, text, scissor );
	}

	// Draw
	inline void FontBatch::Draw (const rect &region, const ext_string &text, bool scissor)
	{
		_font->Draw( *this, region, text, scissor );
	}
	
	// GetTextDimensions
	inline void FontBatch::GetTextDimensions (uni_c_string text, OUT vec2 &dim, OUT usize &lineLength) const
	{
		_font->GetTextDimensions( *this, text, dim, lineLength );
	}
	
	// GetFormattedText
	inline void FontBatch::GetFormattedText (const ext_string &text, float maxLineWidth, const LocaleCharacters &localeChars,
											 OUT vec2 &dim, OUT ext_string &formatted) const
	{
		_font->GetFormattedText( *this, maxLineWidth, text, localeChars, formatted, dim );
	}


}	// Graphics
}	// Engine
